#include "gd32f3x0.h"
#include "stdint.h"
#include "stdio.h"
#include "version.h"
#include "DevicesDelay.h"
#include "DevicesADC.h"


static uint16_t st_ADC0DmaDatas[ADC0_SAMPLING_NUMBER][ADC0_SAMPLING_CHANNEL] = {0};


void vADCInit(void)
{
    /* enable GPIOC clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* enable ADC clock */
    rcu_periph_clock_enable(RCU_ADC);
    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);
    /* config ADC clock */
    rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6);


    /* config the GPIO as analog mode */
    gpio_mode_set(GPIOA, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);


    /* ADC contineous function enable */
    adc_special_function_config(ADC_CONTINUOUS_MODE, ENABLE);
    /* ADC scan mode disable */
    adc_special_function_config(ADC_SCAN_MODE, ENABLE);
    /* ADC data alignment config */
    adc_data_alignment_config(ADC_DATAALIGN_RIGHT);
    /* ADC channel length config */
    adc_channel_length_config(ADC_REGULAR_CHANNEL, ADC0_SAMPLING_CHANNEL);


    /* ADC regular channel config */
    adc_regular_channel_config(ADC_CHANNEL_CURRENT_FILTRATE,  ADC_CHANNEL_0, ADC_SAMPLE_TIME);
    adc_regular_channel_config(ADC_CHANNEL_CURRENT_DUMP,      ADC_CHANNEL_1,  ADC_SAMPLE_TIME);
    adc_regular_channel_config(ADC_CHANNEL_CURRENT_RENEWAL,   ADC_CHANNEL_2,  ADC_SAMPLE_TIME);
    adc_regular_channel_config(ADC_CHANNEL_CURRENT_PACK,      ADC_CHANNEL_3, ADC_SAMPLE_TIME);

    /* ADC trigger config */
    adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE);
    /* ADC external trigger config */
    adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);


    vADC0DMAInit();


    /* enable ADC interface */
    adc_enable();
    vDelayMs(100);
    /* ADC calibration and reset calibration */
    adc_calibration_enable();

    /* ADC software trigger enable */
    adc_software_trigger_enable(ADC_REGULAR_CHANNEL);
}

void vADC0DMAInit(void)
{
    dma_parameter_struct dma_init_struct = {0};

    /* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);

    /* deinitialize DMA channelx(USARTx tx) */
    dma_deinit(DMA_CH0);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)st_ADC0DmaDatas;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_16BIT;
    dma_init_struct.number = ADC0_SAMPLING_NUMBER * ADC0_SAMPLING_CHANNEL;
    dma_init_struct.periph_addr = (uint32_t)(ADC_RDATA);
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_16BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH0, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_enable(DMA_CH0);
    /* enable DMA channelx */
    dma_channel_enable(DMA_CH0);
    /* ADC DMA function enable */
    adc_dma_mode_enable();
}


/*!
    \brief      ADC channel sample
    \param[in]  none
    \param[out] none
    \retval     none
*/
float fADCGetChannelValue(uint8_t channel, uint32_t uiCnt)
{
    uint32_t uiValueSum = 0, i = 0;
    uint16_t usValueNow = 0, usValueMax = 0, usValueMin = 0xFFFF;


    /* ADC regular channel config */
    adc_regular_channel_config(0, channel, ADC_SAMPLE_TIME);

    /* 切换通道后，丢弃第一次转换的数据 */
    /* wait the end of conversion flag */
    while(!adc_flag_get(ADC_FLAG_EOC));
    /* clear the end of conversion flag */
    adc_flag_clear(ADC_FLAG_EOC);
    /* return regular channel sample value */
    (void)adc_regular_data_read();


    for(i = 0; i < uiCnt; ++i)
    {
        /* wait the end of conversion flag */
        while(!adc_flag_get(ADC_FLAG_EOC));
        /* clear the end of conversion flag */
        adc_flag_clear(ADC_FLAG_EOC);
        /* get regular channel sample value */
        usValueNow = adc_regular_data_read();

        uiValueSum += usValueNow;;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < usValueNow) ? usValueNow : usValueMax;
        usValueMin = (usValueMin > usValueNow) ? usValueNow : usValueMin;
    }


    /* 去除最大与最小值 */
    uiValueSum -= (usValueMax + usValueMin);

   return ((float)uiValueSum / (uiCnt - 2) * (3300.0f / 4096.0f));
}

float fADCDMAGetChannelValue(uint8_t ucChannel)
{
    uint16_t usValueMax = 0, usValueMin = 0xFFFF, *pDatasHand = NULL;
    uint32_t uiValueSum = 0, i = 0;

    if(ucChannel >= ADC0_SAMPLING_CHANNEL)
        return 0.0f;

    pDatasHand = (uint16_t *)st_ADC0DmaDatas;
    pDatasHand += ucChannel;

    for(i = 0; i < ADC0_SAMPLING_NUMBER; ++i)
    {
        uiValueSum += *pDatasHand;

        /* 找到最大与最小值 */
        usValueMax = (usValueMax < *pDatasHand) ? *pDatasHand : usValueMax;
        usValueMin = (usValueMin > *pDatasHand) ? *pDatasHand : usValueMin;

        pDatasHand += ADC0_SAMPLING_CHANNEL;
    }

    /* 去除最大与最小值 */
    uiValueSum -= (usValueMax + usValueMin);

    return ((float)uiValueSum / (ADC0_SAMPLING_NUMBER - 2) * (3300.0f / 4095.0f));
}

